package com.sykj.seaflow.warm.module.design.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sykj.seaflow.common.base.bean.PageQuery;
import com.sykj.seaflow.common.base.exception.CommonException;
import com.sykj.seaflow.warm.core.convert.NodeConvertHandler;
import com.sykj.seaflow.warm.core.utils.FlowUtils;
import com.sykj.seaflow.warm.module.def.bean.SeaFlowDef;
import com.sykj.seaflow.warm.module.def.entity.FlowDefExt;
import com.sykj.seaflow.warm.module.def.service.FlowDefExtService;
import com.sykj.seaflow.warm.module.design.entity.SeaFlowDesign;
import com.sykj.seaflow.warm.module.design.mapper.SeaFlowDesignMapper;
import com.sykj.seaflow.warm.module.design.params.*;
import com.sykj.seaflow.warm.module.design.service.SeaFlowDesignService;
import com.sykj.seaflow.warm.module.nodeExt.entity.FlowNodeExt;
import com.sykj.seaflow.warm.module.nodeExt.service.FlowNodeExtService;
import com.warm.flow.core.entity.Node;
import com.warm.flow.core.service.DefService;
import com.warm.flow.core.utils.FlowConfigUtil;
import com.warm.flow.orm.entity.FlowDefinition;
import lombok.AllArgsConstructor;
import org.dom4j.Document;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@AllArgsConstructor
@Service
public class SeaFlowDesignServiceImpl extends ServiceImpl<SeaFlowDesignMapper, SeaFlowDesign>  implements SeaFlowDesignService {

    private final DefService defService;
    private final FlowDefExtService flowDefExtService;
    private final FlowNodeExtService flowNodeExtService;

    @Transactional
    @Override
    public void add(SeaFlowDesignAddParam addParam) {
        // 添加流程设计
        SeaFlowDesign SeaFlowDesign = BeanUtil.copyProperties(addParam, SeaFlowDesign.class);
        SeaFlowDesign.setStatus("1");
        codeExist(addParam.getFlowCode());
        this.save(SeaFlowDesign);
    }

    public void codeExist(String flowCode) {
        QueryWrapper<SeaFlowDesign> query = Wrappers.query();
        query.lambda().eq(SeaFlowDesign::getFlowCode, flowCode);
        SeaFlowDesign one = this.getOne(query);
        Assert.isNull(one);
    }


    @Transactional
    @Override
    public void edit(SeaFlowDesignEditParam editParam) {
        SeaFlowDesign SeaFlowDesign = BeanUtil.copyProperties(editParam, SeaFlowDesign.class);
//        FlowDefinition flowDefinition = BeanUtil.copyProperties(editParam, FlowDefinition.class);
        this.updateById(SeaFlowDesign);
//        defService.updateById(flowDefinition);
//        defService.saveXml();
    }

    @Transactional
    @Override
    public void del(List<SeaFlowDesignIdParam> idParam) {
        List<Long> ids = CollectionUtil.map(idParam, SeaFlowDesignIdParam::getId, true);
        Assert.isTrue(this.removeBatchByIds(ids), "删除失败");
    }

    @Override
    public SeaFlowDesign get(SeaFlowDesignIdParam idParam) {
       return  this.getById(idParam.getId());
    }

    @Override
    public IPage<SeaFlowDesign> page(SeaFlowDesignPageParam pageParam, PageQuery<SeaFlowDesign> pageQuery) {
        LambdaQueryWrapper<SeaFlowDesign> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.like(ObjectUtil.isNotEmpty(pageParam.getFlowCode()), SeaFlowDesign::getFlowCode, pageParam.getFlowCode());
        queryWrapper.like(ObjectUtil.isNotEmpty(pageParam.getFlowName()), SeaFlowDesign::getFlowName, pageParam.getFlowName());
//        queryWrapper.eq(ObjectUtil.isNotEmpty(pageParam.getFlowStatus()), SeaFlowDesign::getFlowStatus, pageParam.getFlowStatus());
        // 分类
        queryWrapper.eq(ObjectUtil.isNotEmpty(pageParam.getCategoryId()), SeaFlowDesign::getCategoryId, pageParam.getCategoryId());

       return this.page(pageQuery.getPageAndSort(), queryWrapper);
    }

    @Override
    public List<SeaFlowDesign> canUseFlow(SeaFlowDesignPageParam pageParam) {
        LambdaQueryWrapper<SeaFlowDesign> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.like(ObjectUtil.isNotEmpty(pageParam.getFlowCode()), SeaFlowDesign::getFlowCode, pageParam.getFlowCode());
        queryWrapper.like(ObjectUtil.isNotEmpty(pageParam.getFlowName()), SeaFlowDesign::getFlowName, pageParam.getFlowName());
        queryWrapper.eq(SeaFlowDesign::getStatus, "1");
        // 版本号存在，说明已经发布了
        queryWrapper.isNotNull(SeaFlowDesign::getFlowVersion);
        queryWrapper.isNotNull(SeaFlowDesign::getDefId);
        queryWrapper.orderByAsc(SeaFlowDesign::getSortNum);
        return this.list(queryWrapper);
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void publish(SeaFlowDesignIdParam idParam) {
        SeaFlowDesign seaFlowDesign = this.getById(idParam.getId());
        // 流程设计配置转流程定义
        SeaFlowDef seaFlowDef = BeanUtil.copyProperties(seaFlowDesign, SeaFlowDef.class);

        String flowJson = seaFlowDesign.getFlowJson();
        List<Node> nodeList = NodeConvertHandler.convert(JSONUtil.parseArray(flowJson), null, null);
        seaFlowDef.setNodeList(nodeList);
        // 保存
        saveFlowDesign(seaFlowDef);
        String version = seaFlowDef.getVersion();
        saveXml(seaFlowDef);

        // 流程设计表 同步最新流程定义信息
        seaFlowDesign.setDefId(seaFlowDef.getId());
        seaFlowDesign.setFlowVersion(version);
        this.updateById(seaFlowDesign);

        //发布
        defService.publish(seaFlowDef.getId());

        // 流程定义扩展信息
        FlowDefExt flowDefExt = new FlowDefExt();
        flowDefExt.setId(seaFlowDef.getId());
        flowDefExt.setFlowJson(seaFlowDesign.getFlowJson());
        flowDefExt.setManagerId(seaFlowDesign.getManagerId());
        flowDefExt.setDesignId(seaFlowDesign.getId());
        flowDefExtService.save(flowDefExt);

        // 节点的扩展信息
//        List<Node> nodeList = SeaFlowDef.getNodeList();
        List<FlowNodeExt> flowDefExts = BeanUtil.copyToList(nodeList, FlowNodeExt.class);
        flowDefExts.forEach(r-> r.setDefId(seaFlowDef.getId()));
        flowNodeExtService.saveBatch(flowDefExts);
    }

    private void saveXml(FlowDefinition flowDefinition) {
        try {
            Document document = FlowConfigUtil.createDocument(flowDefinition);
            flowDefinition.setXmlString(document.asXML());
            System.out.println(document.asXML());
            flowDefinition.setVersion(null);
            defService.saveXml(flowDefinition);
        } catch (Exception e) {
            throw new CommonException(e.getMessage(),e);
        }
    }

    private void upgradeVersion(String flowVersion, SeaFlowDesign seaFlowDesign) {
        String nextVersion = FlowUtils.getNextVersion(flowVersion);
        seaFlowDesign.setFlowVersion(nextVersion);
    }

    private void saveFlowDesign(FlowDefinition flowDefinition) {
        //去掉主键信息， 需要重新生成
        flowDefinition.setId(null);
        flowDefinition.setTenantId(null);
        flowDefinition.setCreateTime(null);
        defService.checkAndSave(flowDefinition);

    }

    @Override
    public void unPublish(SeaFlowDesignIdParam idParam) {

    }

    @Override
    public void saveConfig(SeaFlowDesignConfigParam configParam) {
        SeaFlowDesign SeaFlowDesign = BeanUtil.copyProperties(configParam, SeaFlowDesign.class);
        this.updateById(SeaFlowDesign);
        String flowJson = configParam.getFlowJson();
        System.out.println(flowJson);

    }
}
